﻿namespace HzySocket.WebSocket.Core
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;

    /// <summary>
    /// session 容器
    /// </summary>
    /// <typeparam name="TSession"></typeparam>
    public static class WebSocketSessionContainer<TSession> where TSession : WebSocketSessionBase
    {
        //定义静态对象 缓存 WebSocket 对象
        public static readonly List<TSession> AppSessions;
        private static readonly object lockObj = new object();

        /// <summary>
        /// 
        /// </summary>
        static WebSocketSessionContainer()
        {
            AppSessions = new List<TSession>();
        }

        /// <summary>
        /// 根据条件筛选 Session 对象
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static IEnumerable<TSession> GetAppSessions(Func<TSession, bool> predicate)
        {
            lock (lockObj)
            {
                return AppSessions.Where(predicate).ToList(); // 立即执行，避免延迟执行问题
            }
        }

        /// <summary>
        /// 根据sessionKey 获取 session 对象
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <returns></returns>
        public static TSession GetAppSession(string sessionKey)
        {
            lock (lockObj)
            {
                return AppSessions.Find(w => w.SessionKey == sessionKey); // 立即执行，避免延迟执行问题
            }
        }

        /// <summary>
        /// 获取 所有 session 对象
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<TSession> GetAllAppSessions()
        {
            lock (lockObj)
            {
                return AppSessions;
            }
        }

        /// <summary>
        /// 插入Session 对象
        /// </summary>
        /// <param name="appSession"></param>
        public static void AddAppSession(TSession appSession)
        {
            lock (lockObj)
            {
                AppSessions.Add(appSession);
            }
        }

        /// <summary>
        /// 添加或者更新
        /// </summary>
        /// <param name="appSession"></param>
        public static void AddOrUpdateAppSession(TSession appSession)
        {
            var oldAppSession = GetAppSession(appSession.SessionKey);

            if (oldAppSession == null)
            {
                AddAppSession(appSession);
            }
            else
            {
                lock (lockObj)
                {
                    // 修复：正确更新对象内容而不是替换引用
                    // 这里需要根据实际需求决定是替换整个对象还是更新属性
                    // 如果需要更新属性，应该逐个赋值而不是直接替换引用
                    AppSessions.Remove(oldAppSession);
                    AppSessions.Add(appSession);
                }
            }
        }

        /// <summary>
        /// 移除Session 对象
        /// </summary>
        /// <param name="predicate"></param>
        public static void RemoveSession(Func<TSession, bool> predicate)
        {
            lock (lockObj)
            {
                var sessionsToRemove = AppSessions.Where(predicate).ToList();
                foreach (var session in sessionsToRemove)
                {
                    AppSessions.Remove(session);
                    try
                    {
                        session.WebSocket?.Dispose();
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"Failed to dispose webSocket: {e.Message}");
                    }
                    finally
                    {
                        Console.WriteLine("webSocket 已被释放！" + session.SessionKey);
                    }
                }
            }
        }

        /// <summary>
        /// 获取 session 连接数
        /// </summary>
        /// <returns></returns>
        public static int GetAppSessionCount()
        {
            lock (lockObj)
            {
                return AppSessions.Count;
            }
        }

        /// <summary>
        /// 检查 session 是否存在
        /// </summary>
        /// <returns></returns>
        public static bool Any(Func<TSession, bool> predicate)
        {
            lock (lockObj)
            {
                return AppSessions.Any(predicate);
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <param name="Data"></param>
        public static async Task SendAsync<T>(Func<TSession, bool> predicate, T Data)
        {
            var appSessions = GetAppSessions(predicate).ToList();
            var sendTasks = new List<Task>();

            foreach (var item in appSessions)
            {
                // 为每个发送操作创建独立的任务，避免阻塞
                var sendTask = Task.Run(async () =>
                {
                    try
                    {
                        await item.SendAsync(Data);
                    }
                    catch (Exception ex)
                    {
                        // 记录单个客户端发送异常，不影响其他客户端
                        // 可以添加日志记录或其他异常处理逻辑
                        Console.WriteLine($"Failed to send message to session {item?.SessionKey}: {ex.Message}");
                    }
                });
                sendTasks.Add(sendTask);
            }

            // 等待所有发送任务完成
            await Task.WhenAll(sendTasks);
        }

        /// <summary>
        /// 所有连接用户发送消息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Data"></param>
        public static async Task SendAllAsync<T>(T Data)
        {
            var appSessions = GetAllAppSessions().ToList();
            var sendTasks = new List<Task>();

            foreach (var item in appSessions)
            {
                // 为每个发送操作创建独立的任务，避免阻塞
                var sendTask = Task.Run(async () =>
                {
                    try
                    {
                        await item.SendAsync(Data);
                    }
                    catch (Exception ex)
                    {
                        // 记录单个客户端发送异常，不影响其他客户端
                        // 可以添加日志记录或其他异常处理逻辑
                        Console.WriteLine($"Failed to send message to session {item?.SessionKey}: {ex.Message}");
                    }
                });
                sendTasks.Add(sendTask);
            }

            // 等待所有发送任务完成
            await Task.WhenAll(sendTasks);
        }
    }
}